const Controller = require('../prototype/Controller')
const { models } = require('../model')
const UserModel = models.User
const UserCollection = models.User.collection
const { jwtVerify, passwordClientBcrypt } = require('../service/verify')
const { processLog } = require('../service/userActivity')
const { jwtGen, passwordBcrypt, passwordCompare } = require('../service/verify')
const { initKmSpace } = require('../service/km')

const config = require('../../config/index')
const cookieOption = config.cookieOption

class User extends Controller {
  _signToken (ctx, user) {
    const accessToken = jwtGen({
      _id: user._id,
      name: user.name,
      email: user.email,
      role: 99
    })
    const data = {
      accessToken: accessToken,
      userInfo: {
        _id: user._id,
        name: user.name,
        email: user.email,
        account: user.account
      }
    }
    ctx.cookies.set('x-access-token', accessToken, cookieOption)
    return data
  }

  userFilter () {
    return async (ctx, next) => {
      // 已登录注册用户
      const request = ctx.request
      const accessToken = request.headers['x-access-token'] || ctx.cookies.get('x-access-token')
      if (accessToken) {
        let decoded = {}
        try {
          decoded = await jwtVerify(accessToken)
        } catch (err) {
          console.log('TOKEN ERROR:', accessToken)
        }
        // Token 未过期
        if (decoded.exp > (Date.now() / 1000)) {
          ctx._user = ctx.request._user = await UserModel.findById(decoded.data._id)
          return await next()
        }
      }
      // 已登录临时用户
      const tToken = ctx.request.headers['x-temp-token'] || ctx.cookies.get('x-temp-token')
      let tempUser
      if (tToken) {
        let decoded = {}
        try {
          decoded = await jwtVerify(tToken)
        } catch (err) {
          console.log('TOKEN ERROR:', tToken)
        }
        tempUser = decoded.data
        if (tempUser) {
          ctx._tUser = await UserModel.findById(tempUser._id)
        }
      }
      await next()
    }
  }

  login () {
    return async (ctx) => {
      const { request, response } = ctx
      const body = request.body
      // 查找 email 或者 account
      const userByAccount = await UserCollection.findOne({ account: body.account })
      const userByEmail = await UserCollection.findOne({ email: body.account })
      const userByPhone = await UserCollection.findOne({ phone: body.account })
      const user = userByAccount || userByPhone || userByEmail
      // 查找用户
      if (!user) {
        return response.wrapper.error('HANDLE_ERROR', '没有这个用户')
      }
      if (user.status === 1) {
        return response.wrapper.error('HANDLE_ERROR', '账号已被屏蔽')
      }
      if (user.version !== 1 && body.password.length === 60) {
        return response.wrapper.error('AUTH_VERSION_ERROR', '用户密码版本错误，需要传输一次明文密码进行升级')
      }
      // 比较密码
      const isPasswordCorrect = await passwordCompare(body.password, user.password)
      if (isPasswordCorrect === true) {
        const data = this._signToken(ctx, user)
        // 更新用户安全认证版本
        if (user.version !== 1) {
          await models.User.updateById(user._id, {
            $set: {
              password: await passwordBcrypt(await passwordClientBcrypt(body.password)),
              version: 1
            }
          })
        }
        return response.wrapper.succ(data)
      }
      return response.wrapper.error('HANDLE_ERROR', '密码错误')
    }
  }

  logout () {
    return async (ctx) => {
      ctx.cookies.set('x-access-token')
      ctx.cookies.set('x-temp-token')
      return ctx.wrapper.succ('注销登录成功')
    }
  }

  changePassword () {
    return async ({ request, response }) => {
      const { id, password } = request.body
      const user = await UserCollection.findOne({ id: id })
      if (!user) {
        return response.wrapper.error('HANDLE_ERROR', '没有这个用户')
      }
      if (!(password && password.length >= 6)) {
        return response.wrapper.error('HANDLE_ERROR', '密码格式错误')
      }
      const result = await UserCollection.updateOne({
        _id: user._id
      }, {
        $set: {
          password: await passwordBcrypt(password)
        }
      })
      return response.wrapper(result)
    }
  }

  registry () {
    return async (ctx) => {
      const { request, response } = ctx
      const body = request.body
      // if (request) {
      //     return response.wrapper.error('HANDLE_ERROR', '暂时不开放注册');
      // }
      if (!body.name) {
        return response.wrapper.error('HANDLE_ERROR', '用户名不可为空')
      }
      if (!body.account) {
        return response.wrapper.error('HANDLE_ERROR', '账号不可为空')
      }
      const reEmail = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/
      const rePhone = /^1\d{10}$/
      if (!reEmail.test(body.account) && !rePhone.test(body.account)) {
        return response.wrapper.error('HANDLE_ERROR', '账号必须为邮箱或手机')
      }
      if (!(body.password && body.password.length >= 6)) {
        return response.wrapper.error('HANDLE_ERROR', '密码至少6位')
      }
      // 查重
      const userByAccount = await UserCollection.findOne({ account: body.account })
      if (userByAccount) {
        return response.wrapper.error('HANDLE_ERROR', '已存在同名账号')
      }
      if (body.email) {
        const userByEmail = await UserCollection.findOne({ email: body.email })
        if (userByEmail) {
          return response.wrapper.error('HANDLE_ERROR', '已存在相同邮箱账号')
        }
      }
      // 加密密码
      const password = await passwordBcrypt(body.password)
      // 存在游客账号则进行合并
      let result
      let userId = ctx._tUser._id
      if (ctx._tUser) {
        const tempUser = ctx._tUser
        result = await UserModel.updateById(tempUser._id, {
          $set: {
            name: body.name,
            account: body.account,
            email: body.email,
            role: 1,
            password,
            version: 1
          }
        })
      } else {
        // 直接创建
        result = await UserCollection.insertOne({
          name: body.name,
          account: body.account,
          email: body.email,
          role: 1,
          password,
          version: 1
        })
        userId = result.insertedId
      }
      initKmSpace(userId)
      return response.wrapper.succ(result)
    }
  }

  _extractPublicField (user) {
    return {
      _id: user._id,
      name: user.name,
      role: user.role,
      toolCollection: user.toolCollection,
      toolLike: user.toolLike,
      contentVote: user.contentVote,
      contentCollect: user.contentCollect,
      kmSpaceId: user.kmSpaceId,
      workbenches: user.workbenches
    }
  }

  getCurrentUser () {
    return async (ctx) => {
      // 检查注册用户
      const user = ctx._user
      if (user) {
        this._signToken(ctx, user)
        return ctx.wrapper.succ(this._extractPublicField(ctx._user))
      }
      // 检查游客用户
      const tempUser = ctx._tUser
      // 如果游客用户信息不存在则自动创建
      if (!tempUser) {
        const baseTempUserInfo = {
          name: '游客',
          role: 99
        }
        const result = await UserModel.insertOne({
          ...baseTempUserInfo,
          mark: {
            ip: ctx.request.ip,
            userAgent: ctx.request.headers['user-agent']
          }
        })
        const id = result.insertedId
        const insertedUser = result.ops[0]
        const tempUser = {
          _id: id,
          ...baseTempUserInfo
        }
        const token = jwtGen(tempUser)
        ctx.cookies.set('x-temp-token', token, cookieOption)
        ctx._tUser = insertedUser
      }
      // ctx._tUser
      return ctx.wrapper.succ(this._extractPublicField(ctx._tUser))
    }
  }

  postActivity () {
    return async (ctx) => {
      const log = ctx.request.body // 上传的参数会在body中
      const uaInfo = ctx._uaInfo
      const ip = ctx._ip
      const user = ctx._user || ctx._tUser
      const doc = {
        userId: user._id || '',
        agent: {
          ip: ip,
          userAgent: ctx.request.headers['user-agent'],
          browser: uaInfo.browser,
          os: uaInfo.os
        },
        level: 4, // 默认值
        ...log
      }
      const result = await models.UserLog.insertOne(doc)
      await processLog(result.insertedId)
      return ctx.wrapper.succ(result)
    }
  }

  feedback () {
    return async (ctx) => {
      const data = ctx.request.body // 上传的参数会在body中
      const user = ctx._user
      const doc = {
        userId: user._id,
        content: data.content,
        status: data.status
      }
      const result = await models.UserFeedback.insertOne(doc)
      return ctx.wrapper.succ(result.result)
    }
  }
}

module.exports = User
